An algorithm to find the last nonzero digit of N!
=================================================

(W. Bomfim)

1. The algorithm
----------------

    Given N, the algorithm procceds like the basic base conversion algorithm,
i.e., it determines quotients q, and remainders r, as in the conversion of N to
base 5. Initially two parameters t, and m are both equal to zero; at each
step, when a new pair q, r is determined, the algorithm modifies t, m in such a
way that at the end the final nonzero digit of N! is a function of t, m. In a
notation similar to Knuth's, [1],

Algorithm A. Given an integer N, N>=2, find L equal to the last nonzero digit of
             N!.
A1. [Initialize.] Let q <- N; t <- 0; m <- 0.
A2. [Determine a new pair.] Set r <- q mod 5; q <- [q/5].
A3. [Modify t.] If r is even set t <- t + r.
A4. [q is zero?] If q = 0, make z <- (m + t/2) mod 4; if z = 0, L = 6; otherwise
                 L = 2^z. The algorithm ends; L is the answer.
A5. [Prepare next step.] Make m <- m + q mod 4; go back to A2.


    The execution time of the algorithm is O(log N). This follows from the fact
that at each iteration r is a digit of N in base 5 and the representation of N
in this base has [log_5(N)] + 1 digits. (Here we denote floor(x) by [x], and log
in base 5 of x by log_5(x).)

2. Examples
-----------

2.1) Let N=2; after A1, we have q=2, t = m = 0. After A2 r=2 and q=0. A3 makes t
= 2, and since q = 0, A4 sets z = 1; the algorithm finishes with L = 2.
2.2) With N=3 after A2 r=3, and q=0, so t remains 0, z = 0, and L=6.
2.3) If N = 4 after A2 r = 4, q = 0, so z = 2, and L = 4.


3. A proof that algorithm A is correct
--------------------------------------

LEMMA. For N>=2, algorithm A determines L equal to the final nonzero digit of N!.

    In the previous section we saw that this algorithm is correct for N= 2 to 4.
If N >= 5, we have (1) below, substituting p for 5 in a congruence found in
Concrete Mathematics, [2].


N!/(5^M) # (-l)^M * a_@!...a_1!a_0! (mod 5)                             (1)

where M is the multiplicity of 5 in the factorization of N! , and
      (a_@ ... a_1 a_0)5 is the radix 5 representation of N.

Representing the left size of (1) by the product a.x, and the right term by P,
we get

a.x # P (mod 5),                                                        (2)

and can make

x = N!/( 5^M * 2^M ),                                                   (3)

a = 2^m , and                                                           (4)

P = (-l)^m * a_@!...a_1!a_0!,                                           (5)

where

m # M (mod 4).                                                          (6)

    Identity (4) is valid since (6) implies that 2^M # 2^m (mod 5); (5) is
correct because from (6) both the parities of M and m are the same.

    We can determine P satisfying (2) making Q=( ((a_@!)mod 5)...((a_0!)mod 5));
and

P = Q.(-l)^m.                                                           (7)

    With t equal to the sum of the even a_i's, i = 0,1,..., @; the product Q is
equal to 2^(t/2). This is a fact because if a_i is odd, i.e., a_i = 1, or 3, the
product Q is not modified since 1! mod 5 = 3! mod 5 = 1; naturally we can sum a_i
= 0 in t. Finally, 2! mod 5 = 2 = 2^(2/2), and 4! mod 5 = 4 = 2^(4/2), so
instead of multiply Q by 2, or 4, we respectively add 2, or 4 to t. In the end,

Q = 2^(t/2).                                                            (8)

    Since the parities of m, and c = m mod 4, are both the same, from (2),
(4), and (7), we get the congruence

a.x # Q.(-1)^c (mod 5),                                                 (9)

which is valid, when a = 2^(m mod 4) mod 5, and Q = 2^((t/2)mod 4) mod 5.

    Because both m mod 4, and (t/2) mod 4, can have only values from 0 to 3, (9)
can be written only in the ways showed in the following table. Below we will
denote by L the last nonzero digit of N!. (The module 5 is implicit.)

|        |           | a =   | Q =   |
| c =    | d =       | (2^c) | (2^d) | a.x # Q.(-1)^c    (9)
| m mod 4| (t/2)mod 4| mod 5 | mod 5 |
+--------+-----------+-------+-------+------------------------------------
|   0    |     0     |   1   |   1   | x # 1, L = 1+5 = 6.
|        |     1     |       |   2   | x # 2, L = 2.
|        |     2     |       |   4   | x # 4 => L = 4.
|        |     3     |       |   3   | x # 3 => x # 8 => L = 8.
+--------+-----------+-------+-------+------------------------------------
|   1    |     0     |   2   |   1   | 2x # -1 => 2x # 4, L = 2.
|        |     1     |       |   2   | 2x # -2 => x # -1, L = 4.
|        |     2     |       |   4   | 2x # -4 => x # -2 => L = 8.
|        |     3     |       |   3   | 2x # -3 => 2x # 2 => L = 6.
+--------+-----------+-------+-------+------------------------------------
|   2    |     0     |   4   |   1   | 4x # 1, 4x # -4, x # -1, L = 4.
|        |     1     |       |   2   | 4x # 2, -4x # 8, x # -2, L = 8. (*)
|        |     2     |       |   4   | 4x # 4, x # 1, L = 6.
|        |     3     |       |   3   | 4x # 3, 4x # 8, x # 2, L = 2.
+--------+-----------+-------+-------+------------------------------------
|   3    |     0     |   3   |   1   | 3x # -1, 3x # -6, x # -2, L = 8.
|        |     1     |       |   2   | 3x # -2, 3x # 3, L = 6.
|        |     2     |       |   4   | 3x # -4, 3x # 6, L = 2.
|        |     3     |       |   3   | 3x # -3, L = 4.


(*) Using LAW B of [1] section 1.2.4 we can multiply the terms of 4x # 2
    respectively by (-1) and 4.

    The table below shows that L can be determined by,

z <- (m + t/2) mod 4;
if z is 0, L <- 6, otherwise L <- 2^z.

    For example, let c = m mod 4 = 2, and d = t/2 mod 4 = 0; so z = 2, and L = 4.
We can see L=4 in line "2 0" of the table above.


| m     | (t/2) | (m+t/2) |   |
| mod 4 | mod 4 |  mod 4  | L |
+-------+-------+---------+---+
|   0   |   0   |    0    | 6 |
|       |   1   |    1    | 2 |
|       |   2   |    2    | 4 |
|       |   3   |    3    | 8 |
+-------+-------+---------+---+
|   1   |   0   |    1    | 2 |
|       |   1   |    2    | 4 |
|       |   2   |    3    | 8 |
|       |   3   |    0    | 6 |
+-------+-------+---------+---+
|   2   |   0   |    2    | 4 |
|       |   1   |    3    | 8 |
|       |   2   |    0    | 6 |
|       |   3   |    1    | 2 |
+-------+-------+---------+---+
|   3   |   0   |    3    | 8 |
|       |   1   |    0    | 6 |
|       |   2   |    1    | 2 |
|       |   3   |    2    | 4 |

***


4. PARI Implementation
----------------------

    A straightforward PARI implementation of algorithm A is given by

    while(N = input(), if(N >= 2, {m=0; t=0; N=floor(log(N)/log(5)); for(i = 1, N, aux = N; N = floor(N/5); m += N % 4; a_i = aux -5 * N; t += (1 - a_i % 2) * a_i;); t += (1 -N%2) * N; z = (m + t/2) % 4; L = 6*((2^z)%2) + (1-((2^z)%2))*2^z; print(L);  },{print("Ends when N < 2."); break}))


References
----------
[1] D. E. Knuth, The Art of Computer Programming, vol.1.
[2] Ronald L. Graham, Donald E. Knuth and Oren Patashnik, Concrete Math.; Addison-
Wesley, section 4, exercises 40, and 54.
